home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / pedit.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  16KB  |  680 lines

  1. /*
  2.  * $Id: pedit.c,v 0.91 1994/02/20 00:53:22 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  *  Purpose:
  26.  *   Edit an individual pixel or a group of pixels.
  27.  *
  28.  */
  29. #if !defined(lint) && defined(F_ID)
  30. char *id_pe = "$Id: pedit.c,v 0.91 1994/02/20 00:53:22 zhao Pre-Release $";
  31. #endif
  32.  
  33. #include "bit.h"
  34. #include "extern.h"
  35.  
  36.  
  37. /**************** Local variables *********************************/
  38.  
  39. static int dx = 30, dy = 30;    /* edit region                       */
  40. static int xi, yi;        /* lower left corner of region        */
  41. static long pewin = -1;        /* edit window                        */
  42. static long pewinx, pewiny;    /* window lower left corner           */
  43. static void *pemat;        /* generic matrix                     */
  44. static rgba_t **cpmat;        /* cpack matrix                       */
  45. static ci_t **cmmat;        /* color index matrix                 */
  46. static int pxi = -1, pyi;    /* currently selected pixel in matrix */
  47. static int pc[4];        /* current pixel color                */
  48. static int spc[4];        /* pixel color when first  selected   */
  49. static int gridcol[4];        /* color marks of the grid            */
  50. static int markcol = 1;        /* colors used to mark the selection  */
  51.  
  52. /****************** Local functions ********************************/
  53.  
  54. static int pe_init(IPTR);    /* initialize           */
  55. static void pe_cleanup(void);    /* finish               */
  56. static void pe_set(IPTR);    /* set pix's color      */
  57. static void pe_select(IPTR);    /* select a pix to edit */
  58. static int pe_keybd(int);    /* handle keyboard      */
  59. static int pe_popup(IPTR);    /* handle pop-up        */
  60. static void pe_altkey(IPTR);    /* handle ALTKEY        */
  61.  
  62. static void addto_dirty_pool(void);
  63. static int pe_wm_handler(IPTR, int /* wme */ );
  64. static int draw_pewin(IPTR, int /* win */ );
  65. static void mark_selection(int, int, int);
  66.  
  67. /***************************************************************
  68.  * it would appear that sometines, a mouse Q event is left after
  69.  *  a getbutton call. Eat it
  70.  ****************************************************************/
  71.  
  72. static void
  73. eat_qevent(long dev)
  74. {
  75.     short val;
  76.  
  77.     while (fl_qtest() == dev)
  78.     (void) fl_qread(&val);
  79. }
  80.  
  81. /*********************************************************************
  82.  *   Global entry point from control panel
  83.  *********************************************************************/
  84.  
  85. int
  86. pixel_edit(IPTR im)
  87. {
  88.     short val;
  89.     int done = 0;
  90.  
  91.     /* get the editing region and image matrix */
  92.  
  93.     if (pe_init(im) < 0)
  94.     return -1;
  95.  
  96.     /* how to handle redraw of pewin */
  97.  
  98.     install_multiw_handler(draw_pewin);
  99.     install_wm_handler(pe_wm_handler);
  100.     pe_wm_handler(im, 0);    /* initialize position */
  101.  
  102.  
  103.     /* looping until ESC key or done/cancel from popup entry */
  104.     while (!done)
  105.       {
  106.       /*
  107.        * this might save some CPU cycles since bit_qread never block
  108.        * while fl_do_forms does
  109.        */
  110.  
  111.       while (!fl_qtest())
  112.           fl_do_forms();
  113.  
  114.       /* service all redraw and other Q events */
  115.       switch (bit_qread(&val))
  116.         {
  117.         case MIDDLEMOUSE:
  118.         if (val)
  119.             pe_set(im);
  120.         break;
  121.         case LEFTALTKEY:
  122.         case RIGHTALTKEY:
  123.         if (val)
  124.             pe_altkey(im);
  125.         break;
  126.         case LEFTMOUSE:
  127.         if (val)
  128.             (altkey_down ? pe_set : pe_select) (im);
  129.         break;
  130.         case MENUBUTTON:
  131.         if (val)
  132.             done = pe_popup(im);
  133.         break;
  134.         case KEYBD:
  135.         done = pe_keybd(val);
  136.         break;
  137.         }
  138.       }
  139.  
  140.     /* we want to the change to be made to the image in core */
  141.     if (done > 0)
  142.       {                /* overwrite */
  143.       put_subimage(im, pemat, make_rect(xi, yi, dx, dy), 1);
  144.       dbl_rect_redraw(im, xi, yi, dx, dy);
  145.       }
  146.     pe_cleanup();
  147.     return 0;
  148. }
  149.  
  150. /********* Clean up **********************/
  151. static void
  152. pe_cleanup(void)
  153. {
  154.     short val;
  155.  
  156.     hide_getcolor();
  157.     rubber_finish();
  158.     remove_multiw_handler(draw_pewin);
  159.     remove_wm_handler(pe_wm_handler);
  160.  
  161.     /* handle this redraw first */
  162.     (void) bit_qread(&val);
  163.  
  164.     winclose(pewin);
  165.  
  166.     /* fake a dirty rectangle */
  167.     addto_dirty_pool();
  168.  
  169.     /* signal closing of pixel edit window */
  170.     pewin = -1;
  171.  
  172.     clear_over_pup();
  173.     fl_activate_all_forms();
  174. }
  175.  
  176. /******************************************************************
  177.  * draw a small cross at the currently selected pixle
  178.  ******************************************************************/
  179. static void
  180. mark_selection(int x, int y, int col)
  181. {
  182.     if (x < 0 || pewin <= 0)
  183.     return;
  184.  
  185.     if (winget() != pewin)
  186.     winset(pewin);
  187.  
  188.     switch_frame_buffer();
  189.     color(col);
  190.  
  191.     /* a plus rotated 45 */
  192.     gl_plus(x + pezx / 2, y + pezy / 2,
  193.         pezx - 2, pezy - 2, 0, 450);    /* cross */
  194.     drawmode(NORMALDRAW);
  195. }
  196.  
  197. /*********************************************************************
  198.  * make grid lines. gx and gy are step size
  199.  *********************************************************************/
  200. static void
  201. make_grid(long win, int gcol[], int gx, int gy)
  202. {
  203.     long owin = winget();
  204.     int x, y;
  205.     long xm, ym;
  206.  
  207.     winset(win);
  208.     getsize(&xm, &ym);
  209.  
  210.     Color(Pack(gcol[0], gcol[1], gcol[2]), gcol[3]);
  211.     for (x = gx; x < xm; x += gx)
  212.     draw_line(x, 0, x, ym);
  213.     for (y = gy; y < ym; y += gy)
  214.     draw_line(0, y, xm, y);
  215.  
  216.     if (owin > 0 && owin != win)
  217.     winset(owin);
  218. }
  219.  
  220. /**************************************************************
  221.  * Add the pewin to the dirty pool so that the repaint driver won't
  222.  * do a full redraw
  223.  *************************************************************/
  224. static void
  225. addto_dirty_pool(void)
  226. {
  227.     int bw = 13;
  228.     add_d_rect(pewinx - bw, pewiny - bw,
  229.            pezx * dx + 2 * bw, pezy * dy + 4 * bw);
  230. }
  231.  
  232. /***************************************************************
  233.  * called by repaint thru extra_paint function pointer to repair
  234.  * any damages to pewin.
  235.  ****************************************************************/
  236. /* ARGSUSED */
  237. static int
  238. draw_pewin(IPTR im, int val)
  239. {
  240.     long owin = winget();
  241.     static long xm, ym, ox, oy;
  242.  
  243.     /* local call pass val == -1, dispatcher calls with val == pewin */
  244.     if (pewin <= 0 || (val > 0 && val != pewin))
  245.     return -1;
  246.  
  247.     if (owin != pewin)
  248.     winset(pewin);
  249.  
  250.     if (val > 0)
  251.       {
  252.       getsize(&xm, &ym);
  253.       getorigin(&pewinx, &pewiny);
  254.       reshapeviewport();
  255.       ortho2(-0.5, xm - 0.5, -0.5, ym - 0.5);
  256.       switch_frame_buffer();
  257.       color(0);
  258.       clear();
  259.       drawmode(NORMALDRAW);
  260.       /* add dirty pool only if we know for sure that pewin moved */
  261.       if (ox - pewinx || oy - pewiny)
  262.           addto_dirty_pool();
  263.       }
  264.  
  265.     ox = pewinx;
  266.     oy = pewiny;
  267.  
  268.     /* do the raster */
  269.     rectzoom((float) pezx, (float) pezy);
  270.     if (IS_CPACK(im))
  271.     lrectwrite(0, 0, dx - 1, dy - 1, cpmat[0]);
  272.     else
  273.     rectwrite(0, 0, dx - 1, dy - 1, cmmat[0]);
  274.     rectzoom(1.0, 1.0);
  275.  
  276.     /* also generate  grid */
  277.     if (val > 0)
  278.       {
  279.       make_grid(pewin, gridcol, pezx, pezy);
  280.       }
  281.  
  282.     mark_selection(pxi * pezx, pyi * pezy, markcol);
  283.  
  284.     if (owin != pewin && is_valid_win(owin))
  285.     set_current_window(owin);
  286.  
  287.     return 0;
  288. }
  289.  
  290.  
  291. /*******************************************************************
  292.  * draw a single pixel at (px, py) in matrix
  293.  *******************************************************************/
  294. static void
  295. draw_pixel(IPTR im, int py, int px)
  296. {
  297.     long owin = winget();
  298.     int ppx = px * pezx, ppy = py * pezy;
  299.  
  300.     set_current_window(pewin);
  301.     rectzoom(pezx, pezy);
  302.     if (IS_CI(im))
  303.       {
  304.       rectwrite(ppx, ppy, ppx, ppy, ((ci_t **) pemat)[py] + px);
  305.       }
  306.     else
  307.       {
  308.       lrectwrite(ppx, ppy, ppx, ppy, ((rgba_t **) pemat)[py] + px);
  309.       }
  310.     rectzoom(1., 1.);
  311.     if (owin > 0)
  312.     set_current_window(owin);
  313. }
  314.  
  315. /*****************************************************************
  316.  * Get a rectangular region of the image, which will be
  317.  * the raster we will be editing
  318.  *****************************************************************/
  319. static int
  320. get_edit_matrix(IPTR im)
  321. {
  322.     if (pemat)
  323.     free_mat(pemat);
  324.  
  325.     if (!(pemat = get_subimage(im, xi, yi, dx, dy)))
  326.       {
  327.       Bark("PEInit", "Unable to get submatrix");
  328.       return -1;
  329.       }
  330.     cpmat = pemat;
  331.     cmmat = pemat;
  332.     return 0;
  333. }
  334.  
  335. static void
  336. open_pewin(IPTR im, int ini)
  337. {
  338.     int pww = pezx * dx - 1;
  339.     int pwh = pezy * dy - 1;
  340.     int gx = getgdesc(GD_XPMAX) - 15;
  341.     int gy = getgdesc(GD_YPMAX) - 40;
  342.  
  343.     if (pewin > 0)
  344.     return;
  345.     if (ini)
  346.     /* place it on upper-right corner */
  347.     prefposition(gx - pww, gx, gy - pwh, gy);
  348.     else
  349.     prefposition(pewinx, pewinx + pww, pewiny, pewiny + pwh);
  350.  
  351.     pewin = winopen("PixelEdit");
  352.     getorigin(&pewinx, &pewiny);
  353.     set_cursor(pewin, CUR_S_CROSS);
  354.     set_default_cursor(pewin, CUR_S_CROSS);
  355.  
  356.     if (IS_CPACK(im))
  357.       {
  358.       RGBmode();
  359.       gconfig();
  360.       }
  361. }
  362.  
  363. /***************************************************************
  364.  * select the editing region with a moving rubber band.
  365.  * continuing zooming and moving until a mouse click
  366.  ***************************************************************/
  367. static int
  368. pe_init(IPTR im)
  369. {
  370.     short val;
  371.     long dev;
  372.     int done;
  373.  
  374.     /* we must limit the region size */
  375.     if (dx > im->w)
  376.     dx = im->w;
  377.     if (dy > im->h)
  378.     dx = im->h;
  379.  
  380.     set_rubber_bounds(1, im->xi, im->yi, im->w, im->h);
  381.     set_rubber_obj(RB_RECT);
  382.  
  383.  
  384.     deactivate_all_forms();
  385.  
  386.     xi = im->xi + im->w / 2;
  387.     yi = im->yi + im->h / 2;
  388.  
  389.     if (pewin < 0)
  390.       {
  391.       open_pewin(im, 1);
  392.       }
  393.  
  394.     set_current_window(win_id);
  395.  
  396.     /* warp the mouse */
  397.     set_mouse(xi + win_xo, yi + win_yo);
  398.  
  399.     /* place the rubber */
  400.     do
  401.       {
  402.       done = 0;
  403.       dev = rubber_cursor(win_id, &val, &xi, &yi, dx, dy, 1);
  404.       switch ((dev = bit_handle_event(dev, val)))
  405.         {
  406.         case LEFTMOUSE:
  407.         case MIDDLEMOUSE:
  408.         done = val;
  409.         break;
  410.         default:
  411.         /* must've been moved */
  412.         if (get_edit_matrix(im) < 0)
  413.             return -1;
  414.         draw_pewin(im, -1);
  415.         }
  416.       }
  417.     while (!done);
  418.  
  419.     /* Final matrix */
  420.     if (get_edit_matrix(im) < 0)
  421.     return -1;
  422.     draw_pewin(im, pewin);    /* last time to get grid */
  423.     eat_qevent(MIDDLEMOUSE);
  424.     eat_qevent(LEFTMOUSE);
  425.     return 0;
  426. }
  427.  
  428. /*******************************************************
  429.  * copy a pixel in RGB CI format
  430.  ******************************************************/
  431. static void
  432. cp_pixel(int *des, int *src)
  433. {
  434.     *des++ = *src++;
  435.     *des++ = *src++;
  436.     *des++ = *src++;
  437.     *des = *src;
  438. }
  439.  
  440. /*****************************************************************
  441.  * main control thru popup: Return -1 for cancel, 1 for Done
  442.  * 0: no action
  443.  ****************************************************************/
  444. static int
  445. pe_popup(IPTR im)
  446. {
  447.     static long pemenu = -1;
  448.     int ret = 0;
  449.     int cc;
  450.  
  451.     char *mentry =
  452.     "PixEdit%t|Help%x5|MarkCol%x10|GridCol%x12|Repeat%x18|"
  453.     "Cancel%x20|Done%x50";
  454.  
  455.     if (pemenu < 0)
  456.     pemenu = defpup(mentry);
  457.  
  458.     switch (dopup(pemenu))
  459.       {
  460.       case 5:
  461.       help_cb(0, HELP_PEDIT);
  462.       break;
  463.       case 10:
  464.       ++markcol;
  465.       markcol %= over_pup_colors;
  466.       mark_selection(pxi * pezx, pyi * pezy, markcol);
  467.       break;
  468.       case 12:            /* grid color */
  469.       cc = (~gridcol[0]) & PCMAXV;
  470.       gridcol[0] = gridcol[1] = gridcol[2] = cc;
  471.       if (IS_CI(im))
  472.           gridcol[3] = cmap_closematch(im->cmap,
  473.                     gridcol[0], gridcol[1], gridcol[2]);
  474.       make_grid(pewin, gridcol, pezx, pezy);
  475.       break;
  476.       case 18:            /* do to all pixels having the selected color */
  477.       if (IS_CI(im))
  478.           modify_ci_pixel(cmmat[0], dx * dy, spc[3], pc[3], 0);
  479.       else
  480.           modify_cpack_pixel(cpmat[0], dx * dy,
  481.                  Pack(spc[0], spc[1], spc[2]),
  482.                  Pack(pc[0], pc[1], pc[2]), 0);
  483.       draw_pewin(im, pewin);/* one to get grid on */
  484.       break;
  485.       case 20:            /* cancel */
  486.       ret = -1;
  487.       break;
  488.       case 50:            /* save & return */
  489.       ret = 1;
  490.       break;
  491.       }
  492.     return ret;
  493. }
  494.  
  495. /**************************************************************
  496.  * get pixel position under mouse
  497.  ***************************************************************/
  498. static void
  499. get_pix_pos(int *x, int *y)
  500. {
  501.     int mx, my;
  502.     int px, py;
  503.  
  504.     get_mouse(&mx, &my);
  505.  
  506.     mx -= pewinx;
  507.     my -= pewiny;
  508.  
  509.     /* figure out where the pixel should be */
  510.     px = (mx / pezx);
  511.     py = (my / pezy);
  512.  
  513.     /* check if within pewin (0, dx-1, 0, dy-1) */
  514.     if (px >= 0 && px <= dx - 1 && py >= 0 && py <= dy - 1)
  515.       {
  516.       *x = px;
  517.       *y = py;
  518.       }
  519. }
  520.  
  521.  
  522. /**************************************************************
  523.  * what to do if color changes
  524.  **************************************************************/
  525. static void
  526. handle_color_change(int c[])
  527. {
  528.  
  529.     pack_pixel(imgptr, pemat, pyi, pxi, c);
  530.     draw_pixel(imgptr, pyi, pxi);
  531. }
  532.  
  533. /*****************************************************************
  534.  * Select a new pixel to edit
  535.  ****************************************************************/
  536. static void
  537. pe_select(IPTR im)
  538. {
  539.  
  540.     /* remove last mark */
  541.     mark_selection(pxi * pezx, pyi * pezy, 0);
  542.  
  543.     /* making a new selection and mark it */
  544.     get_pix_pos(&pxi, &pyi);
  545.     mark_selection(pxi * pezx, pyi * pezy, markcol);
  546.  
  547.     pick_pixel(im, pemat, pyi, pxi, spc);
  548.     cp_pixel(pc, spc);
  549.  
  550.     set_getcolor_cb(handle_color_change);
  551.     eat_qevent(LEFTMOUSE);
  552.     /* immediate returns */
  553.     get_color(im, pc, 0);
  554. }
  555.  
  556. /*******************************************************************
  557.  * Set pixel or pixels to last selected color
  558.  *******************************************************************/
  559. static void
  560. pe_set(IPTR im)
  561. {
  562.     int reqalt;
  563.  
  564.     set_current_window(pewin);
  565.     reshapeviewport();
  566.  
  567.     /* initiated by altkey */
  568.     reqalt = altkey_down;
  569.  
  570.     /* turn off last mark */
  571.     mark_selection(pxi * pezx, pyi * pezy, 0);
  572.  
  573.     do
  574.       {
  575.       get_pix_pos(&pxi, &pyi);
  576.       pack_pixel(im, pemat, pyi, pxi, pc);
  577.       draw_pixel(im, pyi, pxi);
  578.       }
  579.     while (mouse_down && (!reqalt || (reqalt && altkey_down)));
  580.  
  581.     /* show it at current location */
  582.     mark_selection(pxi * pezx, pyi * pezy, markcol);
  583. }
  584.  
  585. /******************************************************************
  586.  * Keyboard handler
  587.  ******************************************************************/
  588. static int
  589. pe_keybd(int val)
  590. {
  591.     int ret = 0;
  592.  
  593.     switch (val)
  594.       {
  595.       case 27:
  596.       ret = -1;
  597.       break;
  598.       }
  599.     return ret;
  600. }
  601.  
  602. /*******************************************************************
  603.  * handle main window resize, reposition events
  604.  *******************************************************************/
  605. /*ARGSUSED*/
  606. static int
  607. pe_wm_handler(IPTR im, int wme)
  608. {
  609.     static int lxi, lyi, lwx, lwy;
  610.  
  611.     if (wme)
  612.       {
  613.       /* remove the old rectangle */
  614.       rubber_new(win_id, xi - (win_xo - lwx),
  615.              yi - (win_yo - lwy), dx, dy, 0);
  616.       xi += im->xi - lxi;
  617.       yi += im->yi - lyi;
  618.       /* show at new location */
  619.       rubber_new(win_id, xi, yi, dx, dy, 1);
  620.       }
  621.     lxi = im->xi;
  622.     lyi = im->yi;
  623.     lwx = win_xo;
  624.     lwy = win_yo;
  625.     return 0;
  626. }
  627.  
  628. /****************************************************************
  629.  * LEFT alt key is down
  630.  ****************************************************************/
  631. static void
  632. pe_altkey(IPTR im)
  633. {
  634.     int oc[3];
  635.  
  636.     get_cursor_color(oc);
  637.     set_cursor_color(pc);
  638.  
  639.     set_cursor(pewin, CUR_S_FRECT);
  640.     do
  641.       {
  642.       if (getbutton(LEFTMOUSE) || getbutton(MIDDLEMOUSE))
  643.         {
  644.         pe_set(im);
  645.         }
  646.       }
  647.     while (altkey_down);
  648.  
  649.     eat_qevent(LEFTMOUSE);
  650.     set_cursor_color(oc);
  651.     reset_cursor(pewin);
  652. }
  653.  
  654. /*************************************************************
  655.  * for iconify routines
  656.  ************************************************************/
  657.  
  658. static int iconified;
  659. void
  660. pewin_iconify(void)
  661. {
  662.     if (pewin > 0)
  663.       {
  664.       winclose(pewin);
  665.       pewin = -1;
  666.       iconified = 1;
  667.       }
  668. }
  669.  
  670. void
  671. pewin_de_iconify(void)
  672. {
  673.     if (iconified)
  674.       {
  675.       open_pewin(imgptr, 0);
  676.       draw_pewin(imgptr, pewin);
  677.       iconified = 0;
  678.       }
  679. }
  680.